﻿using System;
using System.Web.Services.Protocols;

namespace BizElements.BusinessLayer
{
    /// <summary>An implementation of <see cref="IMethodRemoter"/> which remotes all method calls to the <b>BizElements.Services.WsMethodReceiver</b> Web service.</summary>
    [System.ComponentModel.DesignerCategoryAttribute("code")]
    [System.Web.Services.WebServiceBindingAttribute(Name = "WsMethodReceiverSoap", Namespace = "http://ElementsFx/BizElements.Services/")]
    public class WsMethodSender : SoapHttpClientProtocol, IMethodRemoter
    {
        /// <summary>
        /// Initializes a new instance of the <b>WsMethodSender</b> class.
        /// </summary>
        public WsMethodSender()
        {
        }

        /// <summary>
        /// Returns <b>true</b> indicating that method calls are remoted and executed in another domain/process.
        /// </summary>
        public bool ImplementsRemoting
        {
            get { return true; }
        }

        #region InvokeMethod.

        /// <summary>Marshals object to process defined by the remoter, executes the method and returns the changed object and method's return value to source domain.</summary>
        /// <param name="obj">Object which is to be marshalled to the defined process and supports the execution 
        /// of the specified method. May be changed in remote domain. Must be marked with 
        /// <see cref="System.SerializableAttribute"/> atribute.</param>
        /// <param name="methodName">Method which is to be executed in the remote domain.</param>
        /// <param name="methodParameters">Method parameters. May not be changed in remote domain. Passed by value.
        /// All parameters must be marked with <see cref="System.SerializableAttribute"/> atribute.</param>
        /// <returns>Method's return value. Must be marked with <see cref="System.SerializableAttribute"/> atribute.</returns>
        public object InvokeMethod(object obj, string methodName, params object[] methodParameters)
        {
            if (methodParameters == null)
                methodParameters = new object[0];

            byte[] serializedBusinessObject = Serializer.SerializeWithBinaryFormater(obj);
            byte[][] serializedMethodParameters = Serializer.SerializeWithBinaryFormater(methodParameters);

            // WS InvokeMethod.
            byte[] serializedRetval = InvokeMethod(ref serializedBusinessObject, methodName, serializedMethodParameters);
            object retval = Serializer.DeserializeWithBinaryFormater(serializedRetval);
            object modifiedBusinessObject = Serializer.DeserializeWithBinaryFormater(serializedBusinessObject);

            // Copy modified values into source object.
            ReflectionUtil.CopyObject(modifiedBusinessObject, obj);
            return retval;
        }

        /// <summary>Web service proxy method.</summary>
        /// <param name="serializedBusinessObject">Serialized business object.</param>
        /// <param name="methodName">Method name.</param>
        /// <param name="serializedMethodParameters">Array of serialized method parameters.</param>
        /// <returns>Serialized method's return value.</returns>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ElementsFx/BizElements.Services/InvokeMethod",
             RequestNamespace = "http://ElementsFx/BizElements.Services/",
             ResponseNamespace = "http://ElementsFx/BizElements.Services/",
             Use = System.Web.Services.Description.SoapBindingUse.Literal,
             ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public byte[] InvokeMethod(ref byte[] serializedBusinessObject, string methodName, byte[][] serializedMethodParameters)
        {
            object[] results = this.Invoke("InvokeMethod",
                new object[] { serializedBusinessObject, methodName, serializedMethodParameters });
            serializedBusinessObject = ((byte[])(results[1]));
            return ((byte[])(results[0]));
        }

        #endregion

        #region InvokeStaticMethod.

        /// <summary>
        /// Marshals method arguments to process defined by the remoter, executes the method and returns the method's return value to source domain.
        /// </summary>
        /// <param name="type">Type which contains the specified static method.</param>
        /// <param name="methodName">Method to be executed.</param>
        /// <param name="methodParameters">Method parameters. May not be changed in remote domain. Passed by value.
        /// All parameters must be marked with <see cref="System.SerializableAttribute"/> atribute.</param>
        /// <returns>Method's return value. Must be marked with <see cref="System.SerializableAttribute"/> atribute.</returns>
        public object InvokeStaticMethod(Type type, string methodName, params object[] methodParameters)
        {
            if (methodParameters == null)
                methodParameters = new object[0];

            byte[] serializedType = Serializer.SerializeWithBinaryFormater(type);
            byte[][] serializedMethodParameters = Serializer.SerializeWithBinaryFormater(methodParameters);
            byte[] serializedRetval = InvokeStaticMethod(serializedType, methodName, serializedMethodParameters);
            object retval = Serializer.DeserializeWithBinaryFormater(serializedRetval);
            return retval;
        }

        /// <summary>
        /// Web service proxy method.
        /// </summary>
        /// <param name="serializedType">Type which contains the specified static method.</param>
        /// <param name="methodName">Method name.</param>
        /// <param name="serializedMethodParameters">Array of serialized method parameters.</param>
        /// <returns>Serialized method's return value.</returns>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ElementsFx/BizElements.Services/InvokeStaticMethod",
             RequestNamespace = "http://ElementsFx/BizElements.Services/",
             ResponseNamespace = "http://ElementsFx/BizElements.Services/",
             Use = System.Web.Services.Description.SoapBindingUse.Literal,
             ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public byte[] InvokeStaticMethod(byte[] serializedType, string methodName, byte[][] serializedMethodParameters)
        {
            object[] results = this.Invoke("InvokeStaticMethod",
                new object[] { serializedType, methodName, serializedMethodParameters });
            return ((byte[])(results[0]));
        }

        #endregion

        #region InvokeMethod.

        /// <summary>Marshals object to process defined by the remoter, executes the generic method and returns the changed object and method's return value to source domain.</summary>
        /// <param name="obj">Object which is to be marshalled to the defined process and supports the execution 
        /// of the specified method. May be changed in remote domain. Must be marked with 
        /// <see cref="System.SerializableAttribute"/> atribute.</param>
        /// <param name="methodName">Method which is to be executed in the remote domain.</param>
        /// <param name="methodParameters">Method parameters. May not be changed in remote domain. Passed by value.
        /// All parameters must be marked with <see cref="System.SerializableAttribute"/> atribute.</param>
        /// <returns>Method's return value. Must be marked with <see cref="System.SerializableAttribute"/> atribute.</returns>
        public object InvokeGenericMethod(object obj, string methodName, params object[] methodParameters)
        {
            if (methodParameters == null)
                methodParameters = new object[0];

            byte[] serializedBusinessObject = Serializer.SerializeWithBinaryFormater(obj);
            byte[][] serializedMethodParameters = Serializer.SerializeWithBinaryFormater(methodParameters);

            // WS InvokeMethod.
            byte[] serializedRetval = InvokeGenericMethod(ref serializedBusinessObject, methodName, serializedMethodParameters);
            object retval = Serializer.DeserializeWithBinaryFormater(serializedRetval);
            object modifiedBusinessObject = Serializer.DeserializeWithBinaryFormater(serializedBusinessObject);

            // Copy modified values into source object.
            ReflectionUtil.CopyObject(modifiedBusinessObject, obj);
            return retval;
        }

        /// <summary>Web service proxy method.</summary>
        /// <param name="serializedBusinessObject">Serialized business object.</param>
        /// <param name="methodName">Method name.</param>
        /// <param name="serializedMethodParameters">Array of serialized method parameters.</param>
        /// <returns>Serialized method's return value.</returns>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ElementsFx/BizElements.Services/InvokeGenericMethod",
             RequestNamespace = "http://ElementsFx/BizElements.Services/",
             ResponseNamespace = "http://ElementsFx/BizElements.Services/",
             Use = System.Web.Services.Description.SoapBindingUse.Literal,
             ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public byte[] InvokeGenericMethod(ref byte[] serializedBusinessObject, string methodName, byte[][] serializedMethodParameters)
        {
            object[] results = this.Invoke("InvokeGenericMethod",
                new object[] { serializedBusinessObject, methodName, serializedMethodParameters });
            serializedBusinessObject = ((byte[])(results[1]));
            return ((byte[])(results[0]));
        }

        #endregion

        #region InvokeStaticMethod.

        /// <summary>Marshals method arguments to process defined by the remoter, executes the generic method and returns the method's return value to source domain.</summary>
        /// <param name="type">Type which contains the specified static method.</param>
        /// <param name="methodName">Method to be executed.</param>
        /// <param name="methodParameters">Method parameters. May not be changed in remote domain. Passed by value.
        /// All parameters must be marked with <see cref="System.SerializableAttribute"/> atribute.</param>
        /// <returns>Method's return value. Must be marked with <see cref="System.SerializableAttribute"/> atribute.</returns>
        public object InvokeGenericStaticMethod(Type type, string methodName, params object[] methodParameters)
        {
            if (methodParameters == null)
                methodParameters = new object[0];

            byte[] serializedType = Serializer.SerializeWithBinaryFormater(type);
            byte[][] serializedMethodParameters = Serializer.SerializeWithBinaryFormater(methodParameters);
            byte[] serializedRetval = InvokeGenericStaticMethod(serializedType, methodName, serializedMethodParameters);
            object retval = Serializer.DeserializeWithBinaryFormater(serializedRetval);
            return retval;
        }

        /// <summary>Web service proxy method.</summary>
        /// <param name="serializedType">Type which contains the specified static method.</param>
        /// <param name="methodName">Method name.</param>
        /// <param name="serializedMethodParameters">Array of serialized method parameters.</param>
        /// <returns>Serialized method's return value.</returns>
        [System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ElementsFx/BizElements.Services/InvokeGenericStaticMethod",
             RequestNamespace = "http://ElementsFx/BizElements.Services/",
             ResponseNamespace = "http://ElementsFx/BizElements.Services/",
             Use = System.Web.Services.Description.SoapBindingUse.Literal,
             ParameterStyle = System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
        public byte[] InvokeGenericStaticMethod(byte[] serializedType, string methodName, byte[][] serializedMethodParameters)
        {
            object[] results = this.Invoke("InvokeGenericStaticMethod",
                new object[] { serializedType, methodName, serializedMethodParameters });
            return ((byte[])(results[0]));
        }

        #endregion
    }
}